// -----------------------------
// Author: 		Dhaenens Gert 
// Creation: 	8/5/2013 9:31:02 PM				
// -----------------------------

#ifndef _LuaFunctionInl_h
#define _LuaFunctionInl_h

#include "LuaObject.h"
#include "LuaRef.h"
#include "LuaStackGuard.h"
#include "Lua.h"
#include "LuaStack.h"
#include "LuaDataType.h"
#include "LuaSafeCall.h"

namespace ObjectLua
{

	namespace Internal
	{

		/*
		//	Used to actually bind
		//	the Function to Lua
		*/
		template<typename R>
		void LuaFunction_0<R>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Function lpFunction)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpFunction);
			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpFunction);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename R>
		int LuaFunction_0<R>::callback(lua_State* lpLuaState)
		{
			Type* lpFunction = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpFunction->call();
		}
		/*
		//	Call the Function
		*/
		template<typename R>
		int LuaFunction_0<R>::call() const
		{
			return SafeCall_0<R>()(m_lpLua,m_lpFunction);
		}



		/*
		//	Used to actually bind
		//	the Function to Lua
		*/
		template<typename R, typename P0>
		void LuaFunction_1<R,P0>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Function lpFunction)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpFunction);
			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpFunction);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename R, typename P0>
		int LuaFunction_1<R,P0>::callback(lua_State* lpLuaState)
		{
			Type* lpFunction = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpFunction->call();
		}
		/*
		//	Call the Function
		*/
		template<typename R, typename P0>
		int LuaFunction_1<R,P0>::call() const
		{
			return SafeCall_1<R,P0>()(m_lpLua,m_lpFunction);
		}


		/*
		//	Used to actually bind
		//	the Function to Lua
		*/
		template<typename R, typename P0, typename P1>
		void LuaFunction_2<R,P0,P1>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Function lpFunction)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpFunction);
			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpFunction);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename R, typename P0, typename P1>
		int LuaFunction_2<R,P0,P1>::callback(lua_State* lpLuaState)
		{
			Type* lpFunction = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpFunction->call();
		}
		/*
		//	Call the Function
		*/
		template<typename R, typename P0, typename P1>
		int LuaFunction_2<R,P0,P1>::call() const
		{
			return SafeCall_2<R,P0,P1>()(m_lpLua,m_lpFunction);
		}


		/*
		//	Used to actually bind
		//	the Function to Lua
		*/
		template<typename R, typename P0, typename P1, typename P2>
		void LuaFunction_3<R,P0,P1,P2>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Function lpFunction)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpFunction);
			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpFunction);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename R, typename P0, typename P1, typename P2>
		int LuaFunction_3<R,P0,P1,P2>::callback(lua_State* lpLuaState)
		{
			Type* lpFunction = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpFunction->call();
		}
		/*
		//	Call the Function
		*/
		template<typename R, typename P0, typename P1, typename P2>
		int LuaFunction_3<R,P0,P1,P2>::call() const
		{
			return SafeCall_3<R,P0,P1,P2>()(m_lpLua,m_lpFunction);
		}

		/*
		//	Used to actually bind
		//	the Function to Lua
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3>
		void LuaFunction_4<R,P0,P1,P2,P3>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Function lpFunction)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpFunction);
			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpFunction);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3>
		int LuaFunction_4<R,P0,P1,P2,P3>::callback(lua_State* lpLuaState)
		{
			Type* lpFunction = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpFunction->call();
		}
		/*
		//	Call the Function
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3>
		int LuaFunction_4<R,P0,P1,P2,P3>::call() const
		{
			return SafeCall_4<R,P0,P1,P2,P3>()(m_lpLua,m_lpFunction);
		}


		/*
		//	Used to actually bind
		//	the Function to Lua
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3, typename P4>
		void LuaFunction_5<R,P0,P1,P2,P3,P4>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Function lpFunction)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpFunction);
			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpFunction);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3, typename P4>
		int LuaFunction_5<R,P0,P1,P2,P3,P4>::callback(lua_State* lpLuaState)
		{
			Type* lpFunction = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpFunction->call();
		}
		/*
		//	Call the Function
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3, typename P4>
		int LuaFunction_5<R,P0,P1,P2,P3,P4>::call() const
		{
			return SafeCall_5<R,P0,P1,P2,P3,P4>()(m_lpLua,m_lpFunction);
		}


		/*
		//	Used to actually bind
		//	the Function to Lua
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
		void LuaFunction_6<R,P0,P1,P2,P3,P4,P5>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Function lpFunction)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpFunction);
			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpFunction);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
		int LuaFunction_6<R,P0,P1,P2,P3,P4,P5>::callback(lua_State* lpLuaState)
		{
			Type* lpFunction = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpFunction->call();
		}
		/*
		//	Call the Function
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
		int LuaFunction_6<R,P0,P1,P2,P3,P4,P5>::call() const
		{
			return SafeCall_6<R,P0,P1,P2,P3,P4,P5>()(m_lpLua,m_lpFunction);
		}


		/*
		//	Used to actually bind
		//	the Function to Lua
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
		void LuaFunction_7<R,P0,P1,P2,P3,P4,P5,P6>::bind(Lua* lpLua, LuaTable* lpTable, const char* name, Function lpFunction)
		{
			LUA_ASSERT(lpLua);
			LUA_ASSERT(name);
			LUA_ASSERT(lpFunction);
			LuaStackGuard stackGuard(lpLua);
			Type* lpObject = new Type(lpLua,lpFunction);
			lpTable->addClosure(name,Type::callback, lpObject);
			delete lpObject;
		}
		/*
		//	Callback for Lua
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
		int LuaFunction_7<R,P0,P1,P2,P3,P4,P5,P6>::callback(lua_State* lpLuaState)
		{
			Type* lpFunction = reinterpret_cast<Type*>(LuaStack::getUserData(lpLuaState,LuaStack::upValueIndex(1)));
			return lpFunction->call();
		}
		/*
		//	Call the Function
		*/
		template<typename R, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
		int LuaFunction_7<R,P0,P1,P2,P3,P4,P5,P6>::call() const
		{
			return SafeCall_7<R,P0,P1,P2,P3,P4,P5,P6>()(m_lpLua,m_lpFunction);
		}

	}

}

#endif